// (C) 2022 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

`timescale 1 ns / 1 ps

`include "espi_header.iv"

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Should a PUT_(MEM/IO)(RD/WR)32_SHORT not finish connected, a completion message has to be pushed onto
// the PC Tx FIFO.  If the command does complete successfully then the FIFO is reset.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

module espi_pc_short_completion_fsm
  (
   // Command Decode
   input logic        rx_detect_command,
   input logic        spiclk_cnt_done_hl,
   input logic        detect_iowr_short,
   input logic        detect_iord_short,
   input logic        detect_memrd_short,
   input logic        detect_short_1b,
   input logic        detect_short_2b,
   input logic        detect_short_4b,

   // Avalon Memory-Mapped I/O Master
   input logic        io_read,
   input logic        io_waitrequest,
   input logic [7:0]  io_readdata,

   // Avalon Memory-Mapped Memory Master
   input logic [1:0]  mem_idx,
   input logic        mem_read,
   input logic        mem_waitrequest,
   input logic [31:0] mem_readdata,

   // Completion Transmit FIFO
   output logic       pc_txfifo_req,
   input logic        pc_txfifo_gnt,
   output logic       pc_txfifo_put,
   output logic [7:0] pc_txfifo_wdata,
   input logic        pc_txfifo_empty,
   output logic       pc_txfifo_avail,

   // Short Read Complete
   input logic        pc_short_data_valid,

   // Globals
   input logic        clk,
   input logic        channel_reset_n
   );

    logic write_cycle_type;
    logic write_tag_length_hi;
    logic write_length_lo;
    logic write_read_data;
    logic write_2nd_byte;
    logic write_3rd_byte;
    logic write_4th_byte;

    always @(posedge clk or negedge channel_reset_n) begin
        if (!channel_reset_n) begin
            pc_txfifo_req       <= 0;
            pc_txfifo_put       <= 0;
            pc_txfifo_wdata     <= 0;
            pc_txfifo_avail     <= 0;
            write_cycle_type    <= 0;
            write_tag_length_hi <= 0;
            write_length_lo     <= 0;
            write_read_data     <= 0;
            write_2nd_byte      <= 0;
            write_3rd_byte      <= 0;
            write_4th_byte      <= 0;
        end // if (!channel_reset_n)
        else begin
            pc_txfifo_put       <= 0;
            write_tag_length_hi <= 0;
            write_length_lo     <= 0;
            write_2nd_byte      <= 0;
            write_3rd_byte      <= 0;
            write_4th_byte      <= 0;
            pc_txfifo_avail     <= pc_txfifo_avail & ~pc_txfifo_empty;
            if (rx_detect_command && spiclk_cnt_done_hl) begin
                pc_txfifo_req    <= detect_iowr_short | detect_iord_short | detect_memrd_short;
                write_cycle_type <= 1'b1;
            end

            if (pc_txfifo_gnt && write_cycle_type) begin
                write_cycle_type <= 0;
                if (detect_iowr_short) begin
                    pc_txfifo_put       <= 1'b1;
                    pc_txfifo_wdata     <= `SUCCESSFUL_COMPLETE;
                    write_tag_length_hi <= 1'b1;
                    
                end
                else begin
                    pc_txfifo_put       <= 1'b1;
                    pc_txfifo_wdata     <= `SUCCESSFUL_COMPLETE_DATA;
                    write_tag_length_hi <= 1'b1;
                end
            end // if (pc_txfifo_gnt)

            if (write_tag_length_hi) begin
                pc_txfifo_put   <= 1'b1;
                pc_txfifo_wdata <= 0;
                write_length_lo <= 1'b1;
            end

            if (write_length_lo) begin
                pc_txfifo_put   <= 1'b1;
                pc_txfifo_wdata <= {detect_short_4b, detect_short_2b, detect_short_1b};
                write_read_data <= detect_memrd_short | detect_iord_short;
            end

            if (write_read_data) begin
                if (!io_waitrequest && io_read) begin
                    pc_txfifo_put   <= 1'b1;
                    pc_txfifo_wdata <= io_readdata;
                end

                if (!mem_waitrequest && mem_read) begin
                    write_2nd_byte  <= detect_short_2b | detect_short_4b;
                    pc_txfifo_put   <= 1'b1;
                    pc_txfifo_wdata <= mem_readdata[mem_idx*8+:8];
                end
            end // if (write_read_data)

            if (write_2nd_byte) begin
                write_3rd_byte  <= detect_short_4b;
                pc_txfifo_put   <= 1'b1;
                pc_txfifo_wdata <= mem_readdata[(mem_idx+1)*8+:8];
            end

            if (write_3rd_byte) begin
                write_4th_byte  <= 1'b1;
                pc_txfifo_put   <= 1'b1;
                pc_txfifo_wdata <= mem_readdata[(mem_idx+2)*8+:8];
            end

            if (write_4th_byte) begin
                pc_txfifo_put   <= 1'b1;
                pc_txfifo_wdata <= mem_readdata[(mem_idx+3)*8+:8];
            end

            if (pc_short_data_valid) begin
                pc_txfifo_avail <= 1'b1;
                pc_txfifo_req   <= 0;
                write_read_data <= 0;
            end
        end // else: !if(!channel_reset_n)
    end // always @ (posedge clk or negedge channel_reset_n)

endmodule // espi_pc_short_completion_fsm
